﻿using Cofe.Core.Entry;
using Cofe.Core.Implements;
using Cofe.Core.Property;
using Cofe.Core.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core.EntryType;

namespace Cofe.Core.Dynamic
{
    /// <summary>
    /// If no supported Interface provider, at least convert them to CofeSystemInfo or CofeDirectoryInfo.
    /// </summary>
    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class CofeInterfaceProvider : IDynamicPropertyInterfaceProvider
    {

        private EntryListTypes getEntryListType(IPropertyHost input)
        {
            if (!(input.SupportedDefinitions.IsPropertySupported(CofeProperties.Type)))
                return EntryListTypes.Unknown;
            if (!(input.SupportedDefinitions.Contains(Cofe.Core.PropertyDefinitions.CofeEntryListDefinitions,
                  PropertyDefinitionComparer.CompareCategory)))
                return EntryListTypes.Unknown;

            string type = input.Behaviors.GetProperty(CofeProperties.Type).ValueAsString;

            return EnumUtils.GetEntryListType(type);
        }

        public bool CanCastAs<T>(IPropertyHost input) where T : IDynamicInterface<Property.IPropertyHost>
        {
            if (typeof(T) == typeof(ICofeSystemInfo))
                return true;

            if (typeof(T) == typeof(ICofeDirectoryInfo))
                return input.SupportedDefinitions.Contains(Cofe.Core.PropertyDefinitions.CofeDirDefinitions,
                    PropertyDefinitionComparer.CompareCategory);

            if (typeof(T) == typeof(ICofeItemInfo))
                return false; //no ICofeItemInfo implementation =<

            if (typeof(T) == typeof(IEntryList))
                return getEntryListType(input) != EntryListTypes.Unknown;

            if (typeof(T) == typeof(IAutoEntryList))
                return getEntryListType(input) == EntryListTypes.AutoEntryList;

            if (typeof(T) == typeof(ICustomEntryList))
                return getEntryListType(input) == EntryListTypes.CustomEntryList;

            if (typeof(T) == typeof(IEntryLink))
                return input.Behaviors.IsPropertySupported(Cofe.Core.CofeEntryLinkProperties.LinkedEntryPH);

            if (typeof(T) == typeof(IEntryTypeInfo))                
                return input.Behaviors.GetProperty(CofeProperties.DefaultInterfaceType).Value.Equals(typeof(IEntryTypeInfo));

            return false;
        }

        public T CastAs<T>(IPropertyHost input) where T : IDynamicInterface<Property.IPropertyHost>
        {
            if (CanCastAs<T>(input))
            {
                if (typeof(T) == typeof(ICofeSystemInfo))
                    return (T)(object)new CofeSystemInfo(input);
                if (typeof(T) == typeof(ICofeDirectoryInfo))
                    return (T)(object)new CofeDirectoryInfo(input);
                if (typeof(T) == typeof(IEntryList))
                {
                    switch (getEntryListType(input))
                    {
                        case EntryListTypes.AutoEntryList :
                            return (T)(object)new AutoEntryList(input);
                        case EntryListTypes.CustomEntryList:
                            return (T)(object)new CustomEntryList(input);
                        default :
                            throw new NotSupportedException();
                    }                    
                }

                if (typeof(T) == typeof(IAutoEntryList))
                    return (T)(object)new AutoEntryList(input);

                if (typeof(T) == typeof(ICustomEntryList))
                    return (T)(object)new CustomEntryList(input);

                if (typeof(T) == typeof(IEntryLink))
                    return (T)(object)new EntryLink(input);

                if (typeof(T) == typeof(IEntryTypeInfo))
                    return (T)(object)new EntryTypeInfo(input);
            }
            throw new NotSupportedException();
        }

        public Type[] CastableInterfaces
        {
            get { return new Type[] { typeof(ICofeSystemInfo), typeof(ICofeDirectoryInfo), typeof(IEntryList), 
                typeof(IAutoEntryList), typeof(ICustomEntryList), typeof(IEntryLink), typeof(IEntryTypeInfo) };
            }
        }

        public Type[] CastableContainers
        {
            get { return new Type[] { typeof(CofeSystemInfo), typeof(CofeDirectoryInfo), typeof(EntryList),
            typeof(AutoEntryList), typeof(CustomEntryList), typeof(EntryLink), typeof(EntryTypeInfo) }; }
        }
    }
}
